<!DOCTYPE html>
<html lang="zh_cn">
<head>
          <title>来玩魔王的咚</title>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta charset="utf-8" />
        <!-- twitter card metadata -->
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="/images/mowang.png">
<meta name="twitter:site" content="">
<meta name="twitter:title" content="GIF、SVG、PNG、图片格式转换">
<meta name="twitter:description" content="<p>GIF动画：利萨如图形；浮点数生成SVG；复数分形图：复数说明，Mandelbrot集分形图，生成PNG图片，base64编码后生成img标签，全彩图，牛顿法求解的分形图；图片格式转换。</p>">
        <!-- OG Tags -->
<meta property="og:url" content="/gopl-gif-svg-png.html"/>
<meta property="og:title" content="来玩魔王的咚 | GIF、SVG、PNG、图片格式转换" />
<meta property="og:description" content="<p>GIF动画：利萨如图形；浮点数生成SVG；复数分形图：复数说明，Mandelbrot集分形图，生成PNG图片，base64编码后生成img标签，全彩图，牛顿法求解的分形图；图片格式转换。</p>" />
        <!-- favicon -->
        <link rel="icon" type="image/png" href="/images/mowang.png">
        <!-- moment.js for date formatting -->
        <script src="/theme/js/moment.js"></script>
        <!-- css -->
        <link rel="stylesheet" type="text/css" href="/theme/css/main.css" />
        <!-- 左边的menu，如果页面高度不够，就跟着滚动，否则文章分类显示不全 -->
        <link rel="stylesheet" type="text/css" href="/theme/css/mycss/menu.css" />
		<script>
			
                /*! grunt-grunticon Stylesheet Loader - v2.1.2 | https://github.com/filamentgroup/grunticon | (c) 2015 Scott Jehl, Filament Group, Inc. | MIT license. */
    
    (function(e){function t(t,n,r,o){"use strict";function a(){for(var e,n=0;u.length>n;n++)u[n].href&&u[n].href.indexOf(t)>-1&&(e=!0);e?i.media=r||"all":setTimeout(a)}var i=e.document.createElement("link"),l=n||e.document.getElementsByTagName("script")[0],u=e.document.styleSheets;return i.rel="stylesheet",i.href=t,i.media="only x",i.onload=o||null,l.parentNode.insertBefore(i,l),a(),i}var n=function(r,o){"use strict";if(r&&3===r.length){var a=e.navigator,i=e.Image,l=!(!document.createElementNS||!document.createElementNS("http://www.w3.org/2000/svg","svg").createSVGRect||!document.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#Image","1.1")||e.opera&&-1===a.userAgent.indexOf("Chrome")||-1!==a.userAgent.indexOf("Series40")),u=new i;u.onerror=function(){n.method="png",n.href=r[2],t(r[2])},u.onload=function(){var e=1===u.width&&1===u.height,a=r[e&&l?0:e?1:2];n.method=e&&l?"svg":e?"datapng":"png",n.href=a,t(a,null,null,o)},u.src="",document.documentElement.className+=" grunticon"}};n.loadCSS=t,e.grunticon=n})(this);(function(e,t){"use strict";var n=t.document,r="grunticon:",o=function(e){if(n.attachEvent?"complete"===n.readyState:"loading"!==n.readyState)e();else{var t=!1;n.addEventListener("readystatechange",function(){t||(t=!0,e())},!1)}},a=function(e){return t.document.querySelector('link[href$="'+e+'"]')},c=function(e){var t,n,o,a,c,i,u={};if(t=e.sheet,!t)return u;n=t.cssRules?t.cssRules:t.rules;for(var l=0;n.length>l;l++)o=n[l].cssText,a=r+n[l].selectorText,c=o.split(");")[0].match(/US\-ASCII\,([^"']+)/),c&&c[1]&&(i=decodeURIComponent(c[1]),u[a]=i);return u},i=function(e){var t,o,a;o="data-grunticon-embed";for(var c in e)if(a=c.slice(r.length),t=n.querySelectorAll(a+"["+o+"]"),t.length)for(var i=0;t.length>i;i++)t[i].innerHTML=e[c],t[i].style.backgroundImage="none",t[i].removeAttribute(o);return t},u=function(t){"svg"===e.method&&o(function(){i(c(a(e.href))),"function"==typeof t&&t()})};e.embedIcons=i,e.getCSS=a,e.getIcons=c,e.ready=o,e.svgLoadedCallback=u,e.embedSVG=u})(grunticon,this);
                
                grunticon(["/theme/css/icons.data.svg.css", "/theme/css/icons.data.png.css", "/theme/css/icons.fallback.css"]);
            </script>
        <noscript><link href="/theme/css/icons.fallback.css" rel="stylesheet"></noscript>
        <!-- menu toggle javascript -->
        <script type="text/javascript">
            document.addEventListener("DOMContentLoaded", initMenu);
            
            function initMenu(){
                var menu = document.getElementById("menu");
                var menulink = document.getElementById("menu-link");
                menulink.addEventListener("click", function toggleMenu(){
                        window.event.preventDefault();
                        menulink.classList.toggle('active');
                        menu.classList.toggle('active');              
                    });
            };
        </script>
        <!-- 不蒜子 -->
        <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

    <meta name="description" content="<p>GIF动画：利萨如图形；浮点数生成SVG；复数分形图：复数说明，Mandelbrot集分形图，生成PNG图片，base64编码后生成img标签，全彩图，牛顿法求解的分形图；图片格式转换。</p>" />

    <meta name="tags" content="gopl" />
    <meta name="tags" content="http" />
  <!-- 替换部分base的样式，看文章时，要再宽一点，右边有很多空间可以撑开 -->
  <link rel="stylesheet" type="text/css" href="/theme/css/mycss/article.css" />

</head>
<body>
    <div role="banner" id="masthead">
        <header>
            <a href="/"><img src="/images/mowang.png" alt="McManus Logo"></a>
                <h1>来玩魔王的咚@骑士救兵</h1>
            <a href="#menu" id="menu-link">more stuff</a>
            <nav id="menu">
                <ul>
                        <li><a href="/tags">tags</a></li>
                            <li><a href="/category/cloud.html">Cloud</a></li>
                            <li><a href="/category/docker.html">Docker</a></li>
                            <li class="active"><a href="/category/go.html">Go</a></li>
                            <li><a href="/category/linux.html">Linux</a></li>
                            <li><a href="/category/python.html">Python</a></li>
                            <li><a href="/category/xue-xi-bi-ji.html">学习笔记</a></li>
                            <li><a href="/category/yun-wei-zi-dong-hua.html">运维自动化</a></li>
                </ul>
            </nav>
        </header>
    </div>
        <div class="page" role="main">
  <div class="article" role="article">
    <article>
        <footer>
            <a name="top"></a>
            <p>
              <time datetime=" 2020-07-08 13:00:00+08:00">
                <script>document.write(moment('2020-07-08 13:00:00+08:00').format('LL'));</script>
              </time>
              ~
              <time datetime=" 2020-07-08 13:00:00+08:00">
                <script>document.write(moment('2020-07-08 13:00:00+08:00').format('LL'));</script>
              </time>
            </p>
        </footer>
        <header>
          <h2>
            GIF、SVG、PNG、图片格式转换
          </h2>
        </header>
      <div class="content">
         <div class="toc">
<ul>
<li><a href="#gif-dong-hua">GIF 动画</a><ul>
<li><a href="#shi-li-dai-ma">示例代码</a></li>
<li><a href="#lissajous-han-shu">lissajous函数</a></li>
<li><a href="#yun-xing">运行</a></li>
<li><a href="#shuo-ming">说明</a></li>
</ul>
</li>
<li><a href="#fu-shu-fen-xing-tu">复数分形图</a><ul>
<li><a href="#fu-shu-shuo-ming">复数说明</a></li>
<li><a href="#shuo-ming_1">说明</a></li>
<li><a href="#shu-chu-dao-web-ye-mian">输出到Web页面</a></li>
</ul>
</li>
<li><a href="#tu-pian-ge-shi-zhuan-huan">图片格式转换</a><ul>
<li><a href="#ge-shi-zhuan-huan">格式转换</a></li>
<li><a href="#ge-shi-jie-ma">格式解码</a></li>
</ul>
</li>
</ul>
</div>
<h3 id="gif-dong-hua"><a class="toclink" href="#gif-dong-hua">GIF 动画</a></h3>
<p>这篇展示 Go 标准库的图像包的使用。创建一系列的位图图像，然后将位图序列编码为 GIF 动画。示例要创建的图像叫做<strong>利萨如图形</strong>（Lissajous-Figure）,是20世纪60年代科幻片中的纤维状视觉效果。利萨如图形是参数化的二维谐振曲线，如示波器x轴和y轴馈电输入的两个正弦波。  </p>
<h4 id="shi-li-dai-ma"><a class="toclink" href="#shi-li-dai-ma">示例代码</a></h4>
<p>先放上完整的示例：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/color&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/gif&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;io&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;math&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;math/rand&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;time&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">palette</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">[]</span><span class="nx">color</span><span class="p">.</span><span class="nx">Color</span><span class="p">{</span><span class="nx">color</span><span class="p">.</span><span class="nx">White</span><span class="p">,</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Black</span><span class="p">}</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="nx">whiteIndex</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="c1">// 画板中的第一种颜色</span><span class="w"></span>
<span class="w">    </span><span class="nx">blackIndex</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="c1">// 画板中的下一种颜色</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">rand</span><span class="p">.</span><span class="nx">Seed</span><span class="p">(</span><span class="nx">time</span><span class="p">.</span><span class="nx">Now</span><span class="p">().</span><span class="nx">UTC</span><span class="p">().</span><span class="nx">UnixNano</span><span class="p">())</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nb">len</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">)</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="o">&amp;&amp;</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Args</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span><span class="w"> </span><span class="o">==</span><span class="w"> </span><span class="s">&quot;web&quot;</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">handler</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">lissajous</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">handler</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;localhost:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">lissajous</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">lissajous</span><span class="p">(</span><span class="nx">out</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">        </span><span class="nx">cycles</span><span class="w">  </span><span class="p">=</span><span class="w"> </span><span class="mi">5</span><span class="w">     </span><span class="c1">// 完整的x振荡器变化的个数</span><span class="w"></span>
<span class="w">        </span><span class="nx">res</span><span class="w">     </span><span class="p">=</span><span class="w"> </span><span class="mf">0.001</span><span class="w"> </span><span class="c1">// 角度分辨率</span><span class="w"></span>
<span class="w">        </span><span class="nx">size</span><span class="w">    </span><span class="p">=</span><span class="w"> </span><span class="mi">100</span><span class="w">   </span><span class="c1">// 图像画布包含[-size, size]</span><span class="w"></span>
<span class="w">        </span><span class="nx">nframes</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">64</span><span class="w">    </span><span class="c1">// 动画中的帧数</span><span class="w"></span>
<span class="w">        </span><span class="nx">delay</span><span class="w">   </span><span class="p">=</span><span class="w"> </span><span class="mi">8</span><span class="w">     </span><span class="c1">// 以10ms为单位的帧间延迟</span><span class="w"></span>
<span class="w">    </span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">freq</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">rand</span><span class="p">.</span><span class="nx">Float64</span><span class="p">()</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">3.0</span><span class="w"> </span><span class="c1">// y振荡器的相对频率</span><span class="w"></span>
<span class="w">    </span><span class="nx">anim</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">gif</span><span class="p">.</span><span class="nx">GIF</span><span class="p">{</span><span class="nx">LoopCount</span><span class="p">:</span><span class="w"> </span><span class="nx">nframes</span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">phase</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.0</span><span class="w"> </span><span class="c1">// phase differencs</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">nframes</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">rect</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">image</span><span class="p">.</span><span class="nx">Rect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="o">*</span><span class="nx">size</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="o">*</span><span class="nx">size</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">img</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">image</span><span class="p">.</span><span class="nx">NewPaletted</span><span class="p">(</span><span class="nx">rect</span><span class="p">,</span><span class="w"> </span><span class="nx">palette</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mf">0.0</span><span class="p">;</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">cycles</span><span class="o">*</span><span class="mi">2</span><span class="o">*</span><span class="nx">math</span><span class="p">.</span><span class="nx">Pi</span><span class="p">;</span><span class="w"> </span><span class="nx">t</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="nx">res</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Sin</span><span class="p">(</span><span class="nx">t</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">y</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Sin</span><span class="p">(</span><span class="nx">t</span><span class="o">*</span><span class="nx">freq</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">phase</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">img</span><span class="p">.</span><span class="nx">SetColorIndex</span><span class="p">(</span><span class="nx">size</span><span class="o">+</span><span class="nb">int</span><span class="p">(</span><span class="nx">x</span><span class="o">*</span><span class="nx">size</span><span class="o">+</span><span class="mf">0.5</span><span class="p">),</span><span class="w"> </span><span class="nx">size</span><span class="o">+</span><span class="nb">int</span><span class="p">(</span><span class="nx">y</span><span class="o">*</span><span class="nx">size</span><span class="o">+</span><span class="mf">0.5</span><span class="p">),</span><span class="w"> </span><span class="nx">blackIndex</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="nx">phase</span><span class="w"> </span><span class="o">+=</span><span class="w"> </span><span class="mf">0.1</span><span class="w"></span>
<span class="w">        </span><span class="nx">anim</span><span class="p">.</span><span class="nx">Delay</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">anim</span><span class="p">.</span><span class="nx">Delay</span><span class="p">,</span><span class="w"> </span><span class="nx">delay</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">anim</span><span class="p">.</span><span class="nx">Image</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">append</span><span class="p">(</span><span class="nx">anim</span><span class="p">.</span><span class="nx">Image</span><span class="p">,</span><span class="w"> </span><span class="nx">img</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">gif</span><span class="p">.</span><span class="nx">EncodeAll</span><span class="p">(</span><span class="nx">out</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">anim</span><span class="p">)</span><span class="w">  </span><span class="c1">// 注意：忽略编码错误</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="lissajous-han-shu"><a class="toclink" href="#lissajous-han-shu">lissajous函数</a></h4>
<p>函数有两个嵌套的循环。外层有64个迭代，每个迭代产生一帧。创建一个201×201大小的画板，使用黑白两种颜色。所有的像素值默认设置为0，就是默认的颜色，这里就是白色。每一个内存循环通过设置一些像素为黑色产生一个新的图像。结果用append追加到anim的帧列表中，并且指定80ms的延迟。最后，帧和延迟的序列被编码成GIF格式，然后写入输出流out。<br>
内层循环运行两个振荡器。x方向的振荡器是正弦函数，y方法也是正弦化的。但是它的频率频率相对于x的震动周期是0~3之间的一个随机数。它的相位相对于x的初始值为0，然后随着每个动画帧增加。该循环在x振荡器完成5个完整周期后停止。每一步它都调用SetColorIndex将对应画板上画的(x,y)位置设置为黑色，即值为1。  </p>
<h4 id="yun-xing"><a class="toclink" href="#yun-xing">运行</a></h4>
<p>main函数调用 lissajous 函数，直接写到标准输出，然后用输出重定向指向一个文件名，就生成gif文件了：</p>
<div class="highlight"><pre><span></span><code>$ go build gopl/ch1/liaasjous
$ ./lissajous &gt;out.gif
</code></pre></div>

<p>不过windows貌似不支持gif了。加上web参数调用程序，直接打开浏览器就能查看，每次刷新都是一张新的图形。</p>
<h1 id="fu-dian-shu-sheng-cheng-svg"><a class="toclink" href="#fu-dian-shu-sheng-cheng-svg">浮点数生成 SVG</a></h1>
<p>该篇举了一个浮点绘图运算的例子。根据传入两个参数的函数 z=f(x,y)，绘出三维的网线状曲面，绘制过程中运用了可缩放矢量图形（Scalable Vector Graphics， SVG），绘制线条的一种标准XML格式。</p>
<h2 id="shi-li-dai-ma_1"><a class="toclink" href="#shi-li-dai-ma_1">示例代码</a></h2>
<p>先放上完整的示例：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// 根据一个三维曲面函数计算并生成SVG，并输出到Web页面</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;io&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;math&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">600</span><span class="p">,</span><span class="w"> </span><span class="mi">320</span><span class="w">            </span><span class="c1">// 以像素表示的画布大小</span><span class="w"></span>
<span class="w">    </span><span class="nx">cells</span><span class="w">         </span><span class="p">=</span><span class="w"> </span><span class="mi">100</span><span class="w">                 </span><span class="c1">// 网格单元的个数</span><span class="w"></span>
<span class="w">    </span><span class="nx">xyrange</span><span class="w">       </span><span class="p">=</span><span class="w"> </span><span class="mf">30.0</span><span class="w">                </span><span class="c1">// 坐标轴的范围，-xyrange ~ xyrange</span><span class="w"></span>
<span class="w">    </span><span class="nx">xyscale</span><span class="w">       </span><span class="p">=</span><span class="w"> </span><span class="nx">width</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nx">xyrange</span><span class="w"> </span><span class="c1">// x 或 y 轴上每个单位长度的像素</span><span class="w"></span>
<span class="w">    </span><span class="nx">zscale</span><span class="w">        </span><span class="p">=</span><span class="w"> </span><span class="nx">height</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="mf">0.4</span><span class="w">        </span><span class="c1">// z轴上每个单位长度的像素</span><span class="w"></span>
<span class="w">    </span><span class="nx">angle</span><span class="w">         </span><span class="p">=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Pi</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">6</span><span class="w">         </span><span class="c1">// x、y轴的角度，30度</span><span class="w"></span>
<span class="w">    </span><span class="nx">color</span><span class="w">         </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;grey&quot;</span><span class="w">              </span><span class="c1">// 线条的颜色</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">sin30</span><span class="p">,</span><span class="w"> </span><span class="nx">cos30</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Sin</span><span class="p">(</span><span class="nx">angle</span><span class="p">),</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Cos</span><span class="p">(</span><span class="nx">angle</span><span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">svg</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&lt;svg xmlns=&#39;http://www.w3.org/2000/svg&#39; &quot;</span><span class="o">+</span><span class="w"></span>
<span class="w">        </span><span class="s">&quot;style=&#39;stroke: %s; fill: white; stroke-width: 0.7&#39; &quot;</span><span class="o">+</span><span class="w"></span>
<span class="w">        </span><span class="s">&quot;width=&#39;%d&#39; height=&#39;%d&#39;&gt;&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">color</span><span class="p">,</span><span class="w"> </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">cells</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">cells</span><span class="p">;</span><span class="w"> </span><span class="nx">j</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">ax</span><span class="p">,</span><span class="w"> </span><span class="nx">ay</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">corner</span><span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">bx</span><span class="p">,</span><span class="w"> </span><span class="nx">by</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">corner</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">cx</span><span class="p">,</span><span class="w"> </span><span class="nx">cy</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">corner</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">dx</span><span class="p">,</span><span class="w"> </span><span class="nx">dy</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">corner</span><span class="p">(</span><span class="nx">i</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="o">+</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&lt;polygon points=&#39;%g,%g %g,%g %g,%g %g,%g&#39;/&gt;\n&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w">                </span><span class="nx">ax</span><span class="p">,</span><span class="w"> </span><span class="nx">ay</span><span class="p">,</span><span class="w"> </span><span class="nx">bx</span><span class="p">,</span><span class="w"> </span><span class="nx">by</span><span class="p">,</span><span class="w"> </span><span class="nx">cx</span><span class="p">,</span><span class="w"> </span><span class="nx">cy</span><span class="p">,</span><span class="w"> </span><span class="nx">dx</span><span class="p">,</span><span class="w"> </span><span class="nx">dy</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintln</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;&lt;/svg&gt;&quot;</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">corner</span><span class="p">(</span><span class="nx">i</span><span class="p">,</span><span class="w"> </span><span class="nx">j</span><span class="w"> </span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">float64</span><span class="p">,</span><span class="w"> </span><span class="kt">float64</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 求出网格单元(i,j)的顶点坐标(x,y)</span><span class="w"></span>
<span class="w">    </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">xyrange</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="nb">float64</span><span class="p">(</span><span class="nx">i</span><span class="p">)</span><span class="o">/</span><span class="nx">cells</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">0.5</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">y</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">xyrange</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="p">(</span><span class="nb">float64</span><span class="p">(</span><span class="nx">j</span><span class="p">)</span><span class="o">/</span><span class="nx">cells</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mf">0.5</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 计算曲面高度z</span><span class="w"></span>
<span class="w">    </span><span class="nx">z</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">f</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="c1">// 将(x,y,z)等角投射到二维SVG绘图平面上，坐标是(sx,sy)</span><span class="w"></span>
<span class="w">    </span><span class="nx">sx</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">width</span><span class="o">/</span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="o">-</span><span class="nx">y</span><span class="p">)</span><span class="o">*</span><span class="nx">cos30</span><span class="o">*</span><span class="nx">xyscale</span><span class="w"></span>
<span class="w">    </span><span class="nx">sy</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">height</span><span class="o">/</span><span class="mi">2</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="p">(</span><span class="nx">x</span><span class="o">+</span><span class="nx">y</span><span class="p">)</span><span class="o">*</span><span class="nx">sin30</span><span class="o">*</span><span class="nx">xyscale</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">z</span><span class="o">*</span><span class="nx">zscale</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">sx</span><span class="p">,</span><span class="w"> </span><span class="nx">sy</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">f</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="kt">float64</span><span class="p">)</span><span class="w"> </span><span class="kt">float64</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">r</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Hypot</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="p">)</span><span class="w"> </span><span class="c1">// 到(0,0)的距离</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">math</span><span class="p">.</span><span class="nx">Sin</span><span class="p">(</span><span class="nx">r</span><span class="p">)</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="nx">r</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">handler</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">w</span><span class="p">.</span><span class="nx">Header</span><span class="p">().</span><span class="nx">Set</span><span class="p">(</span><span class="s">&quot;Content-Type&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;image/svg+xml&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">svg</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">handler</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;localhost:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<h4 id="shuo-ming"><a class="toclink" href="#shuo-ming">说明</a></h4>
<p>corner函数返回两个值，构成网格单元其中一个格子的坐标。<br>
理解这段程序需要一些几何知识。这段程序本质上是三套不同坐标系的相互映射，见下图。首先是一个包含 100×100 个单元的二维网络，每个网络单元用整数坐标 (i, j) 标记，从最远处靠后的角落 (0, 0) 开始。从后向前绘制，就如左侧的图，因而后方的多边形可能被前方的遮住。  </p>
<p><img alt="坐标系映射" src="/images/go/02_ch3-02.png"></p>
<p>再看中间的图，在这个坐标系内，网络由三维浮点数 (x, y, z) 决定，其中x和y由i和j的线性函数决定，经过坐标转换，原点处于中央，并且坐标系按照xyrange进行缩放。高度值z由曲面函数 f(x,y) 决定。<br>
最右边的图，这个坐标系是二维成像绘图平面（image canvas），原点在左上角。这个平面中点的坐标记作 (sx, sy)。这里用等角投影（isometric projection）将三维坐标点 (x, y, z) 映射到二维绘图平面上。若一个点的x值越大，y值越小，则其在绘图平面上看起来就越接近右方。而若一个点的x值或y值越大，且z值越小，则其在绘图平面上看起来就越接近下方。纵向 (x) 与横向 (y) 的缩放系数是由30度角的正弦值和余弦值推导而得。z方向的缩放系数为0.4，是个随意决定的参数值。<br>
回到左边那张图的小图，二维网络中的单元由main函数处理，它算出多边形ABCD在绘图平面上四个顶点的坐标，其中B对应 (i, j) ，A、C、D则为其它三个顶点，然后再输出一条SVG指令将其绘出。  </p>
<h3 id="fu-shu-fen-xing-tu"><a class="toclink" href="#fu-shu-fen-xing-tu">复数分形图</a></h3>
<p>该篇通过复数的计算，生成 PNG 格式的分形图。  </p>
<h4 id="fu-shu-shuo-ming"><a class="toclink" href="#fu-shu-shuo-ming">复数说明</a></h4>
<p>Go具备了两种大小的复数 complex64 和 complex128，二者分别由 float32 和 float64 构成。内置的 complex 函数根据给定的实部和虚部创建复数，而内置的 real 函数和 imag 函数则分别提取复数的实部和虚部：</p>
<div class="highlight"><pre><span></span><code><span class="kd">var</span><span class="w"> </span><span class="nx">x</span><span class="w"> </span><span class="kt">complex128</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">complex</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span><span class="w"> </span><span class="mi">2</span><span class="p">)</span><span class="w">  </span><span class="c1">// 1+2i</span><span class="w"></span>
<span class="c1">// x := 1 + 2i</span><span class="w"></span>
<span class="kd">var</span><span class="w"> </span><span class="nx">y</span><span class="w"> </span><span class="kt">complex128</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nb">complex</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="mi">4</span><span class="p">)</span><span class="w">  </span><span class="c1">// 3+4i</span><span class="w"></span>
<span class="c1">// y := 3 + 4i</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nx">x</span><span class="o">*</span><span class="nx">y</span><span class="p">)</span><span class="w">  </span><span class="c1">// -5+10i</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nb">real</span><span class="p">(</span><span class="nx">x</span><span class="o">*</span><span class="nx">y</span><span class="p">))</span><span class="w">  </span><span class="c1">// -5</span><span class="w"></span>
<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="nb">imag</span><span class="p">(</span><span class="nx">x</span><span class="o">*</span><span class="nx">y</span><span class="p">))</span><span class="w">  </span><span class="c1">// 10</span><span class="w"></span>

<span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="m">1i</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="m">1i</span><span class="p">)</span><span class="w">  </span><span class="c1">// -1</span><span class="w"></span>
</code></pre></div>

<h2 id="shi-li-dai-ma_2"><a class="toclink" href="#shi-li-dai-ma_2">示例代码</a></h2>
<p>先放上完整的示例：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// 生成一个PNG格式的Mandelbrot分形图</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/color&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/png&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;math/cmplx&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">        </span><span class="nx">xmin</span><span class="p">,</span><span class="w"> </span><span class="nx">ymin</span><span class="p">,</span><span class="w"> </span><span class="nx">xmax</span><span class="p">,</span><span class="w"> </span><span class="nx">ymax</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">+</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">+</span><span class="mi">2</span><span class="w"></span>
<span class="w">        </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="w">          </span><span class="p">=</span><span class="w"> </span><span class="mi">1024</span><span class="p">,</span><span class="w"> </span><span class="mi">1024</span><span class="w"></span>
<span class="w">    </span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">img</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">image</span><span class="p">.</span><span class="nx">NewRGBA</span><span class="p">(</span><span class="nx">image</span><span class="p">.</span><span class="nx">Rect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">py</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">py</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">height</span><span class="p">;</span><span class="w"> </span><span class="nx">py</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">y</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">py</span><span class="p">)</span><span class="o">/</span><span class="nx">height</span><span class="o">*</span><span class="p">(</span><span class="nx">ymax</span><span class="o">-</span><span class="nx">ymin</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">ymin</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">px</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">px</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">width</span><span class="p">;</span><span class="w"> </span><span class="nx">px</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">px</span><span class="p">)</span><span class="o">/</span><span class="nx">height</span><span class="o">*</span><span class="p">(</span><span class="nx">xmax</span><span class="o">-</span><span class="nx">xmin</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">xmin</span><span class="w"></span>
<span class="w">            </span><span class="nx">z</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">complex</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="c1">// 点(px, py)表示复数值z</span><span class="w"></span>
<span class="w">            </span><span class="nx">img</span><span class="p">.</span><span class="nx">Set</span><span class="p">(</span><span class="nx">px</span><span class="p">,</span><span class="w"> </span><span class="nx">py</span><span class="p">,</span><span class="w"> </span><span class="nx">mandelbrot</span><span class="p">(</span><span class="nx">z</span><span class="p">))</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">OpenFile</span><span class="p">(</span><span class="s">&quot;p1.png&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">O_WRONLY</span><span class="p">|</span><span class="nx">os</span><span class="p">.</span><span class="nx">O_CREATE</span><span class="p">,</span><span class="w"> </span><span class="mo">0666</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;ERROR&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">defer</span><span class="w"> </span><span class="nx">f</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">png</span><span class="p">.</span><span class="nx">Encode</span><span class="p">(</span><span class="nx">f</span><span class="p">,</span><span class="w"> </span><span class="nx">img</span><span class="p">)</span><span class="w">  </span><span class="c1">// 注意：忽略错误</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">mandelbrot</span><span class="p">(</span><span class="nx">z</span><span class="w"> </span><span class="kt">complex128</span><span class="p">)</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Color</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">iterations</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">200</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">contrast</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="kt">complex128</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">uint8</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">iterations</span><span class="p">;</span><span class="w"> </span><span class="nx">n</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">v</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">v</span><span class="o">*</span><span class="nx">v</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">z</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">cmplx</span><span class="p">.</span><span class="nx">Abs</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Gray</span><span class="p">{</span><span class="mi">255</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">contrast</span><span class="o">*</span><span class="nx">n</span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Black</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这个程序用 complex128 运算生成一个 Mandelbrot 集。  </p>
<h4 id="shuo-ming_1"><a class="toclink" href="#shuo-ming_1">说明</a></h4>
<p>两个嵌套循环在 1024×1024 的灰度图上逐行扫描每个点，这个图表示复平面上-2~+2的区域，每个点都对应一个复数，该程序针对各个点反复迭代计算其平方与自身的和，判断其最终能否超出半径为2的圆（取模）。然后根据超出边界所需的迭代次数设定点的灰度。在设定的迭代次数内没有超出的那部分点，这些点属于 Mandelbrot 集，就是黑色的内些部分。最后输出PNG图片。  </p>
<h4 id="shu-chu-dao-web-ye-mian"><a class="toclink" href="#shu-chu-dao-web-ye-mian">输出到Web页面</a></h4>
<p>这次将PNG写到img标签里，并且不生成图片文件，而是用base64对图片进行编码：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;encoding/base64&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/color&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/png&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;log&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;math/cmplx&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;net/http&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">var</span><span class="w"> </span><span class="nx">f</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">z</span><span class="w"> </span><span class="kt">complex128</span><span class="p">)</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Color</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Println</span><span class="p">(</span><span class="s">&quot;http://localhost:8000/?f=newton&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">handler</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">,</span><span class="w"> </span><span class="nx">r</span><span class="w"> </span><span class="o">*</span><span class="nx">http</span><span class="p">.</span><span class="nx">Request</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nx">ParseForm</span><span class="p">();</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">log</span><span class="p">.</span><span class="nx">Print</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">v</span><span class="p">,</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">r</span><span class="p">.</span><span class="nx">Form</span><span class="p">[</span><span class="s">&quot;f&quot;</span><span class="p">];</span><span class="w"> </span><span class="nx">ok</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">switch</span><span class="w"> </span><span class="nx">v</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="s">&quot;newton&quot;</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;2&quot;</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="nx">f</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">newton</span><span class="w"></span>
<span class="w">            </span><span class="k">default</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="nx">f</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">mandelbrot</span><span class="w"></span>
<span class="w">            </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>

<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprint</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">`&lt;body&gt;`</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprint</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">`&lt;img src=&quot;data:image/png;base64,`</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">createPng</span><span class="p">(</span><span class="nx">w</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprint</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">`&quot; /&gt;`</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprint</span><span class="p">(</span><span class="nx">w</span><span class="p">,</span><span class="w"> </span><span class="s">`&lt;/body&gt;`</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">http</span><span class="p">.</span><span class="nx">HandleFunc</span><span class="p">(</span><span class="s">&quot;/&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">handler</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">log</span><span class="p">.</span><span class="nx">Fatal</span><span class="p">(</span><span class="nx">http</span><span class="p">.</span><span class="nx">ListenAndServe</span><span class="p">(</span><span class="s">&quot;localhost:8000&quot;</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">createPng</span><span class="p">(</span><span class="nx">w</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nx">ResponseWriter</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">        </span><span class="nx">xmin</span><span class="p">,</span><span class="w"> </span><span class="nx">ymin</span><span class="p">,</span><span class="w"> </span><span class="nx">xmax</span><span class="p">,</span><span class="w"> </span><span class="nx">ymax</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">-</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">+</span><span class="mi">2</span><span class="p">,</span><span class="w"> </span><span class="o">+</span><span class="mi">2</span><span class="w"></span>
<span class="w">        </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="w">          </span><span class="p">=</span><span class="w"> </span><span class="mi">1024</span><span class="p">,</span><span class="w"> </span><span class="mi">1024</span><span class="w"></span>
<span class="w">    </span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">img</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">image</span><span class="p">.</span><span class="nx">NewRGBA</span><span class="p">(</span><span class="nx">image</span><span class="p">.</span><span class="nx">Rect</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">width</span><span class="p">,</span><span class="w"> </span><span class="nx">height</span><span class="p">))</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">py</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">py</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">height</span><span class="p">;</span><span class="w"> </span><span class="nx">py</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">y</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">py</span><span class="p">)</span><span class="o">/</span><span class="nx">height</span><span class="o">*</span><span class="p">(</span><span class="nx">ymax</span><span class="o">-</span><span class="nx">ymin</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">ymin</span><span class="w"></span>
<span class="w">        </span><span class="k">for</span><span class="w"> </span><span class="nx">px</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="nx">px</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">width</span><span class="p">;</span><span class="w"> </span><span class="nx">px</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">float64</span><span class="p">(</span><span class="nx">px</span><span class="p">)</span><span class="o">/</span><span class="nx">height</span><span class="o">*</span><span class="p">(</span><span class="nx">xmax</span><span class="o">-</span><span class="nx">xmin</span><span class="p">)</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">xmin</span><span class="w"></span>
<span class="w">            </span><span class="nx">z</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">complex</span><span class="p">(</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">y</span><span class="p">)</span><span class="w"></span>
<span class="w">            </span><span class="c1">// 点(px, py)表示复数值z</span><span class="w"></span>
<span class="w">            </span><span class="nx">img</span><span class="p">.</span><span class="nx">Set</span><span class="p">(</span><span class="nx">px</span><span class="p">,</span><span class="w"> </span><span class="nx">py</span><span class="p">,</span><span class="w"> </span><span class="nx">f</span><span class="p">(</span><span class="nx">z</span><span class="p">))</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">b64w</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">base64</span><span class="p">.</span><span class="nx">NewEncoder</span><span class="p">(</span><span class="nx">base64</span><span class="p">.</span><span class="nx">StdEncoding</span><span class="p">,</span><span class="w"> </span><span class="nx">w</span><span class="p">)</span><span class="w">  </span><span class="c1">// 往b64w里写，就是编码后写入到w</span><span class="w"></span>
<span class="w">    </span><span class="k">defer</span><span class="w"> </span><span class="nx">b64w</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span><span class="w"></span>
<span class="w">    </span><span class="nx">png</span><span class="p">.</span><span class="nx">Encode</span><span class="p">(</span><span class="nx">b64w</span><span class="p">,</span><span class="w"> </span><span class="nx">img</span><span class="p">)</span><span class="w"> </span><span class="c1">// 注意：忽略错误</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">mandelbrot</span><span class="p">(</span><span class="nx">z</span><span class="w"> </span><span class="kt">complex128</span><span class="p">)</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Color</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">iterations</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">200</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">contrast</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">15</span><span class="w"></span>
<span class="w">    </span><span class="kd">var</span><span class="w"> </span><span class="nx">v</span><span class="w"> </span><span class="kt">complex128</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">uint8</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">iterations</span><span class="p">;</span><span class="w"> </span><span class="nx">n</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">v</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">v</span><span class="o">*</span><span class="nx">v</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">z</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">cmplx</span><span class="p">.</span><span class="nx">Abs</span><span class="p">(</span><span class="nx">v</span><span class="p">)</span><span class="w"> </span><span class="p">&gt;</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="mi">255</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="nx">contrast</span><span class="o">*</span><span class="nx">n</span><span class="w"></span>
<span class="w">            </span><span class="k">switch</span><span class="w"> </span><span class="nx">n</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">1</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Black</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="c1">// f(x) = x^4 - 1</span><span class="w"></span>
<span class="c1">//</span><span class="w"></span>
<span class="c1">// z&#39; = z - f(z)/f&#39;(z)</span><span class="w"></span>
<span class="c1">//    = z - (z^4 - 1) / (4 * z^3)</span><span class="w"></span>
<span class="c1">//    = z - (z - 1/z^3) / 4</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">newton</span><span class="p">(</span><span class="nx">z</span><span class="w"> </span><span class="kt">complex128</span><span class="p">)</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Color</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">iterations</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">37</span><span class="w"></span>
<span class="w">    </span><span class="kd">const</span><span class="w"> </span><span class="nx">contrast</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">7</span><span class="w"></span>
<span class="w">    </span><span class="k">for</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nb">uint8</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="nx">iterations</span><span class="p">;</span><span class="w"> </span><span class="nx">i</span><span class="o">++</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">z</span><span class="w"> </span><span class="o">-=</span><span class="w"> </span><span class="p">(</span><span class="nx">z</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="mi">1</span><span class="o">/</span><span class="p">(</span><span class="nx">z</span><span class="o">*</span><span class="nx">z</span><span class="o">*</span><span class="nx">z</span><span class="p">))</span><span class="w"> </span><span class="o">/</span><span class="w"> </span><span class="mi">4</span><span class="w"></span>
<span class="w">        </span><span class="k">if</span><span class="w"> </span><span class="nx">cmplx</span><span class="p">.</span><span class="nx">Abs</span><span class="p">(</span><span class="nx">z</span><span class="o">*</span><span class="nx">z</span><span class="o">*</span><span class="nx">z</span><span class="o">*</span><span class="nx">z</span><span class="o">-</span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="p">&lt;</span><span class="w"> </span><span class="mf">1e-6</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="c1">// return color.Gray{255 - contrast*i}</span><span class="w"></span>
<span class="w">            </span><span class="nx">x</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">contrast</span><span class="o">*</span><span class="nx">i</span><span class="w"></span>
<span class="w">            </span><span class="k">switch</span><span class="w"> </span><span class="nx">i</span><span class="w"> </span><span class="o">%</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">0</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">1</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="k">case</span><span class="w"> </span><span class="mi">2</span><span class="p">:</span><span class="w"></span>
<span class="w">                </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">RGBA</span><span class="p">{</span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">,</span><span class="w"> </span><span class="nx">x</span><span class="p">}</span><span class="w"></span>
<span class="w">            </span><span class="p">}</span><span class="w"></span>
<span class="w">        </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">color</span><span class="p">.</span><span class="nx">Black</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这里还增加一个的图形，运用牛顿法求某个函数的复数解（z^4-1=0）。原来的图形这次做成了彩图。  </p>
<h3 id="tu-pian-ge-shi-zhuan-huan"><a class="toclink" href="#tu-pian-ge-shi-zhuan-huan">图片格式转换</a></h3>
<p>image 包下有3个子包：</p>
<ul>
<li>image.gif</li>
<li>image.jpeg</li>
<li>image.png</li>
</ul>
<p>所以，这3种图片格式是标准库原生支持的。  </p>
<h4 id="ge-shi-zhuan-huan"><a class="toclink" href="#ge-shi-zhuan-huan">格式转换</a></h4>
<p>标准库的 image 包导出了 Decode 函数，它从 io.Reader 读取数据，并且识别使用哪一种图像格式来编码数据，调用适当的解碼器，返回 image.Image 对象作为结果。使用 image.Decode 可以构建一个简单的图像转换器，读取某一种格式的图像，然后输出为另外一个格式：</p>
<div class="highlight"><pre><span></span><code><span class="c1">// 读取 PNG 图像，并把它作为 JPEG 图像保存</span><span class="w"></span>
<span class="kn">package</span><span class="w"> </span><span class="nx">main</span><span class="w"></span>

<span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;fmt&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;image/jpeg&quot;</span><span class="w"></span>
<span class="w">    </span><span class="nx">_</span><span class="w"> </span><span class="s">&quot;image/png&quot;</span><span class="w"> </span><span class="c1">// 注册 PNG ×××</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;io&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;os&quot;</span><span class="w"></span>
<span class="w">    </span><span class="s">&quot;path/filepath&quot;</span><span class="w"></span>
<span class="p">)</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">fileName</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="s">&quot;test&quot;</span><span class="w">   </span><span class="c1">// 不要扩展名</span><span class="w"></span>
<span class="w">    </span><span class="nx">dir</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Getwd</span><span class="p">()</span><span class="w"> </span><span class="c1">// 返回当前文件路径的字符串和一个err信息，忽略err</span><span class="w"></span>
<span class="w">    </span><span class="nx">pngPath</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">filepath</span><span class="p">.</span><span class="nx">Join</span><span class="p">(</span><span class="nx">dir</span><span class="p">,</span><span class="w"> </span><span class="nx">fileName</span><span class="o">+</span><span class="s">&quot;.png&quot;</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="nx">jpgPath</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">filepath</span><span class="p">.</span><span class="nx">Join</span><span class="p">(</span><span class="nx">dir</span><span class="p">,</span><span class="w"> </span><span class="nx">fileName</span><span class="o">+</span><span class="s">&quot;.jpg&quot;</span><span class="p">)</span><span class="w"></span>

<span class="w">    </span><span class="c1">// 打开 png 文件</span><span class="w"></span>
<span class="w">    </span><span class="nx">pngFile</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Open</span><span class="p">(</span><span class="nx">pngPath</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="c1">// 文件可能不存在</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;ERROR: %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">os</span><span class="p">.</span><span class="nx">Exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">defer</span><span class="w"> </span><span class="nx">pngFile</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span><span class="w"></span>

<span class="w">    </span><span class="c1">// 创建 jpg 文件</span><span class="w"></span>
<span class="w">    </span><span class="nx">jpgFile</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">os</span><span class="p">.</span><span class="nx">Create</span><span class="p">(</span><span class="nx">jpgPath</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;ERROR: %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">os</span><span class="p">.</span><span class="nx">Exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="k">defer</span><span class="w"> </span><span class="nx">jpgFile</span><span class="p">.</span><span class="nx">Close</span><span class="p">()</span><span class="w"></span>

<span class="w">    </span><span class="c1">// 调用文件转换</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">toJPEG</span><span class="p">(</span><span class="nx">pngFile</span><span class="p">,</span><span class="w"> </span><span class="nx">jpgFile</span><span class="p">);</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintf</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;jpeg: %v\n&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w"></span>
<span class="w">        </span><span class="nx">os</span><span class="p">.</span><span class="nx">Exit</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">toJPEG</span><span class="p">(</span><span class="nx">in</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Reader</span><span class="p">,</span><span class="w"> </span><span class="nx">out</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Writer</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">img</span><span class="p">,</span><span class="w"> </span><span class="nx">kind</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">image</span><span class="p">.</span><span class="nx">Decode</span><span class="p">(</span><span class="nx">in</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">        </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span><span class="w"></span>
<span class="w">    </span><span class="p">}</span><span class="w"></span>
<span class="w">    </span><span class="nx">fmt</span><span class="p">.</span><span class="nx">Fprintln</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stderr</span><span class="p">,</span><span class="w"> </span><span class="s">&quot;Input format =&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">kind</span><span class="p">)</span><span class="w"></span>
<span class="w">    </span><span class="k">return</span><span class="w"> </span><span class="nx">jpeg</span><span class="p">.</span><span class="nx">Encode</span><span class="p">(</span><span class="nx">out</span><span class="p">,</span><span class="w"> </span><span class="nx">img</span><span class="p">,</span><span class="w"> </span><span class="o">&amp;</span><span class="nx">jpeg</span><span class="p">.</span><span class="nx">Options</span><span class="p">{</span><span class="nx">Quality</span><span class="p">:</span><span class="w"> </span><span class="mi">95</span><span class="p">})</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>该程序打开一个png文件，再创建一个新的jpg文件，然后进行图像格式的转换。<br>
注意空白导入"image/png"。如果没有这一行，程序可以正常编译和链接，但是不能识别和解码 PNG 格式的输入：</p>
<div class="highlight"><pre><span></span><code>PS H:\Go\src\gopl\ch10\jpeg&gt; go run main.go
jpeg: image: unknown format
exit status 1
PS H:\Go\src\gopl\ch10\jpeg&gt;
</code></pre></div>

<p>这个例子里是解码png格式的图片，程序能识别png格式是因为上面的一行空导入。也可以支持其他格式，并且是同时支持的，只要多导入几个包。具体看下面的展开。  </p>
<h4 id="ge-shi-jie-ma"><a class="toclink" href="#ge-shi-jie-ma">格式解码</a></h4>
<p>接下来解释它是如何工作的。标准库提供 GIF、PNG、JPEG 等格式的解码库，用户自己可以提供其他格式的，但是为了使可执行程序简短，除非明确需要，否则解碼器不会被包含进应用程序。image.Decode 函数查阅一个关于支持格式的表格。每一个表项由4个部分组成：</p>
<ul>
<li>格式的名字</li>
<li>某种格式中所使用的相同的前缀字符串，用来识别编码格式</li>
<li>一个用来解码被编码图像的函数 Decode</li>
<li>另一个函数 DecodeConfig，它仅仅解码图像的元数据，比如尺寸和色域</li>
</ul>
<p>对于每一种格式，通常通过在其支持的包的初始化函数中来调用 image.RegisterFormat 来向表格添加项。例如 image.png 中的实现如下：</p>
<div class="highlight"><pre><span></span><code><span class="kn">package</span><span class="w"> </span><span class="nx">png</span><span class="w"> </span><span class="c1">// image/png</span><span class="w"></span>

<span class="kd">func</span><span class="w"> </span><span class="nx">Decode</span><span class="p">(</span><span class="nx">r</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Reader</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">image</span><span class="p">.</span><span class="nx">Image</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">DecodeConfig</span><span class="p">(</span><span class="nx">r</span><span class="w"> </span><span class="nx">io</span><span class="p">.</span><span class="nx">Reader</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nx">image</span><span class="p">.</span><span class="nx">Config</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"></span>

<span class="kd">const</span><span class="w"> </span><span class="nx">pngHeader</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">&quot;\x89PNG\r\n\x1a\n&quot;</span><span class="w"></span>
<span class="kd">func</span><span class="w"> </span><span class="nx">init</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w">    </span><span class="nx">image</span><span class="p">.</span><span class="nx">RegisterFormat</span><span class="p">(</span><span class="s">&quot;png&quot;</span><span class="p">,</span><span class="w"> </span><span class="nx">pngHeader</span><span class="p">,</span><span class="w"> </span><span class="nx">Decode</span><span class="p">,</span><span class="w"> </span><span class="nx">DecodeConfig</span><span class="p">)</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</code></pre></div>

<p>这个效果就是，一个应用只需要空白导入格式化所需的包，就可以让 image.Decode 函数具备应对格式的解码能力。<br>
所以，可以多导入几个空包，这样程序就可以支持更多格式的解码了。  </p>
      </div>
      <div class="back-to-top">
        <a href="/">HOME</a>
        <a href="#top">TOP</a>
      </div>
    </article>
  </div>
<!-- end article -->
<!-- 页面往下滚动一段之后才会显示TOC -->
<script>
  window.onscroll = function() {
    var tocbox = document.getElementsByClassName('toc')[0];
    var osTop = document.documentElement.scrollTop || document.body.scrollTop;
    var osWidth = document.documentElement.scrollWidth || document.body.scrollWidth;
    // console.log(osTop)
    if (osTop>300 && osWidth>865) {
      tocbox.style.display = "block"
    }
    if (osTop<300 || osWidth<865) {
      tocbox.style.display = "none"
    }
  }
</script>
                <footer>
                    <div class="icons">
                    </div>
                    <span id="busuanzi_container_page_pv" style="padding: 10px">本文阅读量<span id="busuanzi_value_page_pv"></span>次</span>
                    <span id="busuanzi_container_site_pv" style="padding: 10px">本站总访问量<span id="busuanzi_value_site_pv"></span>次</span>
                    <span id="busuanzi_container_site_uv" style="padding: 10px">本站总访客数<span id="busuanzi_value_site_uv"></span>人</span>
                    <p>© <script>document.write(moment().format('YYYY'));</script> 749B</p>
                </footer>
        </div>
</body>
</html>